//
// Created by ZLY on 2025/5/7.
//
#include "game.h"

#include <fstream>

#include "../scene_main.h"
#include "object_screen.h"
#include "object_world.h"
#include "actor.h"
#include "../player.h"
#include "../scene_title.h"
#include "../affiliate/sprite.h"

void Game::run() {
    while (is_running) {
        if (next_scene_) {
            changeScene(next_scene_);
            next_scene_ = nullptr;
        }
        auto start_time = SDL_GetTicksNS();
        handleEvents();
        update(dt_);
        render();
        const auto end_time = SDL_GetTicksNS();
        const auto frame_time = end_time - start_time;
        if (frame_time < frameDelay) {
            SDL_DelayNS(frameDelay - frame_time); // 将纳秒转换为纳秒
            dt_ = frameDelay / 1e9f; // 将纳秒转换为秒
        } else {
            dt_ = frame_time / 1e9f;
        }
        // SDL_Log("FPS: %f 帧", 1.0f / dt_);
    }
    clean();
}

void Game::init(const std::string title, int width, int height) {
    screen_size_ = glm::vec2(width, height);
    // 初始化SDL3
    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL init error: %s", SDL_GetError());
    }
    // 初始化SDL3_mixer
    if (Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG) != (MIX_INIT_MP3 | MIX_INIT_OGG)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MIX init error: %s", SDL_GetError());
    }
    // 打开音频
    if (!Mix_OpenAudio(0, nullptr)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "mix open error: %s", SDL_GetError());
    }
    // 分配音频通道
    Mix_AllocateChannels(16);
    // 设置音乐声音
    Mix_VolumeMusic(MIX_MAX_VOLUME / 4);
    // 设置音效声音
    Mix_Volume(-1, MIX_MAX_VOLUME / 4);
    // 初始化TTF
    if (!TTF_Init()) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "TTF open error: %s", SDL_GetError());
    }
    // 创建窗口与渲染器
    SDL_CreateWindowAndRenderer(title.c_str(), width, height, SDL_WINDOW_RESIZABLE, &window_, &renderer_);
    SDL_SetRenderLogicalPresentation(renderer_, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX);

    ttf_engine_ = TTF_CreateRendererTextEngine(renderer_);

    frameDelay = 1000000000 / FPS; // 计算帧延迟
    resource_store_ = new ResourceStore(renderer_); // 创建资源管理器
    // current_scene_ = new SceneMain(); // 创建场景
    current_scene_ = new SceneTitle(); // 创建场景
    current_scene_->init(); // 初始化场景
}

void Game::handleEvents() {
    SDL_Event event;
    // 事件循环
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_EVENT_QUIT:
                is_running = false;
                break;
            default:
                current_scene_->handleEvents(event); // 处理事件
                break;
        }
    }
}

void Game::update(float dt) {
    updateMouse();
    current_scene_->update(dt); // 更新场景
}

void Game::render() {
    SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255); // 设置渲染颜色
    SDL_RenderClear(renderer_); // 清除渲染器
    current_scene_->render(); // 渲染场景
    SDL_RenderPresent(renderer_); // 显示渲染器
}

void Game::clean() {
    if (current_scene_) {
        current_scene_->clean();
        delete current_scene_;
    }
    if (resource_store_) {
        resource_store_->clear();
        delete resource_store_;
    }
    if (ttf_engine_) {
        TTF_DestroyRendererTextEngine(ttf_engine_);
    }

    if (renderer_) {
        SDL_DestroyRenderer(renderer_);
        renderer_ = nullptr;
    }
    if (window_) {
        SDL_DestroyWindow(window_);
        window_ = nullptr;
    }
    Mix_CloseAudio();
    Mix_Quit();
    TTF_Quit();
    SDL_Quit();
    SDL_Log("游戏已退出!");
}

void Game::drawGrid(const glm::vec2 &top_left, const glm::vec2 &bottom_right, float grad_with, SDL_FColor fcolor) {
    SDL_SetRenderDrawColorFloat(renderer_, fcolor.r, fcolor.g, fcolor.b, fcolor.a);
    for (float x = top_left.x; x <= bottom_right.x; x += grad_with) {
        SDL_RenderLine(renderer_, x, top_left.y, x, bottom_right.y);
    }
    for (float y = top_left.y; y <= bottom_right.y; y += grad_with) {
        SDL_RenderLine(renderer_, top_left.x, y, bottom_right.x, y);
    }
    SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255); // 恢复默认颜色
}

void Game::drawBoundry(const glm::vec2 &top_left, const glm::vec2 &bottom_right, float boundry_width,
                       SDL_FColor fcolor) {
    SDL_SetRenderDrawColorFloat(renderer_, fcolor.r, fcolor.g, fcolor.b, fcolor.a);
    for (float i = 0; i < boundry_width; i++) {
        SDL_FRect rect = {
            top_left.x - i,
            top_left.y - i,
            bottom_right.x - top_left.x + 2 * i,
            bottom_right.y - top_left.y + 2 * i
        };
        SDL_RenderRect(renderer_, &rect); // 绘制矩形边框
    }

    SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255); // 恢复默认颜色
}

void Game::renderTexture(const Texture &texture, const glm::vec2 &pos, const glm::vec2 &size, const glm::vec2 &mask) {
    SDL_FRect src_rect = {
        texture.src_rect.x,
        texture.src_rect.y + texture.src_rect.h * (1 - mask.y),
        texture.src_rect.w * mask.x,
        texture.src_rect.h * mask.y
    };
    SDL_FRect dst_rect = {
        pos.x,
        pos.y + size.y * (1 - mask.y),
        size.x * mask.x,
        size.y * mask.y
    }; // 目标矩形
    SDL_RenderTextureRotated(renderer_, texture.texture, &src_rect, &dst_rect, texture.angle, nullptr,
                             texture.flip); // 渲染纹理
}

TTF_Text *Game::createTTF_Text(const std::string text, const std::string font_path, int font_size) {
    auto font = resource_store_->getFont(font_path, font_size);
    return TTF_CreateText(ttf_engine_, font, text.c_str(), 0);
}


void Game::renderFillCircle(const glm::vec2 &position, const glm::vec2 &size, float alpha) {
    auto texture = resource_store_->getTexture("resources/UI/circle.png");
    SDL_FRect dst_rect = {position.x, position.y, size.x, size.y};
    SDL_SetTextureAlphaModFloat(texture, alpha);
    SDL_RenderTexture(renderer_, texture, nullptr, &dst_rect);
}

void Game::renderHBar(const glm::vec2 &position, const glm::vec2 &size, float percent, SDL_FColor color) {
    SDL_SetRenderDrawColorFloat(renderer_, color.r, color.g, color.b, color.a);
    SDL_FRect boundary_rect = {position.x, position.y, size.x, size.y};
    SDL_FRect fill_rect = {
        position.x,
        position.y,
        size.x * percent,
        size.y
    };
    SDL_RenderRect(renderer_, &boundary_rect);
    SDL_RenderFillRect(renderer_, &fill_rect);
    SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255); // 恢复默认颜色
}

void Game::setScore(int score) {
    if (score > high_score_) {
        high_score_ = score;
    }
    score_ = score;
}

void Game::addScore(int score) {
    setScore(score_ + score);
}

bool Game::isMouseInRect(const glm::vec2 &top_left, const glm::vec2 &bottom_right) {
    if (mouse_position_.x >= top_left.x && mouse_position_.x <= bottom_right.x && mouse_position_.y >= top_left.y &&
        mouse_position_.y <= bottom_right.y) {
        return true;
    }
    return false;
}

void Game::changeScene(Scene *scene) {
    if (current_scene_) {
        current_scene_->clean();
        delete current_scene_;
    }
    current_scene_ = scene;
    current_scene_->init();
}

void Game::safeChangeScene(Scene *scene) {
    next_scene_ = scene;
}

std::string Game::loadTextFile(const std::string &path) {
    std::ifstream file(path);
    std::string line;
    std::string text;
    while (std::getline(file, line)) {
        text += line + "\n";
    }
    return text;
}

void Game::drawPoint(std::vector<glm::vec2> &points, glm::vec2 render_pos, SDL_FColor color) {
    SDL_SetRenderDrawColorFloat(renderer_, color.r, color.g, color.b, color.a);
    for (auto point: points) {
        SDL_FPoint point_rect = {point.x + render_pos.x, point.y + render_pos.y};
        SDL_RenderPoint(renderer_, point_rect.x, point_rect.y);
    }
    SDL_SetRenderDrawColorFloat(renderer_, 0, 0, 0, 1);
}

void Game::updateMouse() {
    mouse_button_flags_ = SDL_GetMouseState(&mouse_position_.x, &mouse_position_.y);
    int w, h;
    // SDL_FRect rect;
    SDL_GetWindowSize(window_, &w, &h);
    SDL_SetWindowAspectRatio(window_, screen_size_.x / screen_size_.y, screen_size_.x / screen_size_.y);
    mouse_position_ *= screen_size_ / glm::vec2(w, h);
    // SDL_GetRenderLogicalPresentationRect(renderer_, &rect);
    // mouse_position_ = (mouse_position_ - glm::vec2(rect.x, rect.y)) * screen_size_ / glm::vec2(rect.w, rect.y);
}
